/**
 * 
 */
package daytrader.lib;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import daytrader.data.DataModel;
import daytrader.data.TickData;
import daytrader.data.DataAPI;
import daytrader.types.Stock;
import daytrader.types.Sector;
import daytrader.common.Constants;

/**
 * @author fangda	
 * @author Ryan
 *
 *	An interface for data acquisition from daytrader.data, used by daytrader.lib
 *
 */
public class LibData implements LibDataInterface {
	
	private DataModel mydata;
	private String mystock;
	
	/**
	 * 	Default constructor
	 *  Use default generator configure file
	 *  "./src/daytrader/data/" 
	 *  for now
	 */
	public LibData() {
		mydata = new DataModel(Constants.DEFAULT_DATA_PATH);
	}

	public LibData(String dataPath) {
		mydata = new DataModel(dataPath);
	}
	
	/**
	 * 	interface to open data feed for a certain stock
	 *  @param currStock	target stock
	 *  @return true if successfully open, otherwise return false
	 */
	public boolean openStockFeed(Stock currStock) {
		
		String [] stocknames = mydata.listStockNames();
		for (String tmp : stocknames) {
			if (currStock.company_name().compareTo(tmp) == 0) {
				mystock = currStock.company_name();
				return true;
			}
		}
		return false;
	}

	/**
	 * 	interface to open data feed for a certain stock
	 *  @param currname	name of target stock
	 *  @return true if successfully open, otherwise return false
	 */
	public boolean openStockFeed(String currname) {
		
		String [] stocknames = mydata.listStockNames();
		for (String tmp : stocknames) {
			if (currname.compareTo(tmp) == 0) {
				mystock = currname;
				return true;
			}
		}
		return false;
	}
	public String getCurrStockFeed() {
		return mystock;
	}

	/**
	 * 
	 * A wrapper class around TickData[], for conveying a range in a tick array
	 * This avoids copying the range into a new array each time (which will be once per display update
	 *
	 */
	public class TickRange
	{
	    public int start;      // start = first index
	    public int end;        // end = past-last index
	    public TickData[] data;
	    
	    public TickData tick(int i)
	    {
	        assert (i >= 0);
	        assert (i < end - start);
	        
	        return data[start + i];
	    }
	}
	
	/**
	 *  Get a sequence of ticks ending right now
	 *  
	 * @param len      The length of the sequence (# of ticks)
	 * @return         A TickRange object specifying the tick range 
	 */
	public TickRange getTicks(int len, String stockName)
	{
	    assert (len > 0);
	    
        Date today = new Date();
        TickRange tr = new TickRange();
        tr.data = mydata.getTickDataOfToday(stockName);
        tr.end = getTickIndex(today) + 1;
        tr.start = tr.end - len;
        if (tr.start < 0) tr.start = 0;
        
        return tr;
	}
	
	public double open(int day, String stockName)
        {
           	Date today = new Date();
		TickData[] data = mydata.getTickDataOfToday(stockName);
		int i = getTickIndex(today) - day;
		if (i < 0) i = 0;
		if (i > DataAPI.numberTicksPerDay - 1) i = DataAPI.numberTicksPerDay - 1;
		return data[i].open;
        }
	/**
	 * 	Get the open price of a day in the past. 
	 * 	Complexity should be constant time, with amortized data transfer overhead.
	 * 
	 * @param day	the number of days before today (0 for today, positive for history)
	 * @return		open price
	 */
	public double open(int day)
	{
		return open(day, mystock);
	}

	public double close(int day, String stockName)
	{
		Date today = new Date();
		TickData[] data = mydata.getTickDataOfToday(stockName);
		int i = getTickIndex(today) - day;
		if (i < 0) i = 0;
		if (i > DataAPI.numberTicksPerDay - 1) i = DataAPI.numberTicksPerDay - 1;
		return data[i].close;
	}
	/**
	 * 	Get the close price of a day in the past
	 * 	Complexity should be constant time, with amortized data transfer overhead.
	 * 
	 * @param day	the number of days before today (0 for today, positive for history)
	 * @return		close price
	 */
	public double close(int day)
	{
	        return close(day, mystock);
        }

        public double high(int day, String stockName)
	{
		Date today = new Date();
		TickData[] data = mydata.getTickDataOfToday(stockName);
		int i = getTickIndex(today) - day;
		if (i < 0) i = 0;
		if (i > DataAPI.numberTicksPerDay - 1) i = DataAPI.numberTicksPerDay - 1;
		return data[i].high;
	}
	/**
	 * 	Get the high price of a day in the past
	 * 	Complexity should be constant time, with amortized data transfer overhead.
	 * 
	 * @param day	the number of days before today (0 for today, positive for history)
	 * @return		high price
	 */
	public double high(int day)
	{
	        return high(day, mystock);
        }

   	public double low(int day, String stockName)
	{
		Date today = new Date();
		TickData[] data = mydata.getTickDataOfToday(stockName);
		int i = getTickIndex(today) - day;
		if (i < 0) i = 0;
		if (i > DataAPI.numberTicksPerDay - 1) i = DataAPI.numberTicksPerDay - 1;
		return data[i].low;
	}
	/**
	 * 	Get the low price of a day in the past
	 * 	Complexity should be constant time, with amortized data transfer overhead.
	 * 
	 * @param day	the number of days before today (0 for today, positive for history)
	 * @return		low price
	 */
	public double low(int day)
	{
	        return low(day, mystock);
        }
      	public double volume(int day, String stockName)
	{
		Date today = new Date();
		TickData[] data = mydata.getTickDataOfToday(stockName);
		int i = getTickIndex(today) - day;
		if (i < 0) i = 0;
		if (i > DataAPI.numberTicksPerDay - 1) i = DataAPI.numberTicksPerDay - 1;
		return data[i].volume;
	}
	/**
	 * 	Get the volume value of a day in the past
	 * 	Complexity should be constant time, with amortized data transfer overhead.
	 * 
	 * @param day	the number of days before today (0 for today, positive for history)
	 * @return		volume value
	 */
	public double volume(int day)
	{
	        return volume(day, mystock);
        }
	public double dayopen()
        {
                return mydata.getTickDataOfToday(mystock)[0].open;
        }

	public double dayclose()
        {
                return mydata.getTickDataOfToday(mystock)[0].close;
        }

	public double dayhigh()
        {
                return mydata.getTickDataOfToday(mystock)[0].high;                
        }

	public double daylow()
        {
                return mydata.getTickDataOfToday(mystock)[0].low;                
        }

        public double dayvolume()
        {
                return mydata.getTickDataOfToday(mystock)[0].volume;                
        }
	
	public double open()
	{
		return open(0);
	}
	public double close()
	{
		return close(0);
	}
	public double high()
	{
		return high(0);
	}
	public double low()
	{
		return low(0);
	}
	public double volume()
	{
		return volume(0);
	}
	public String[] listStockNames()
	{
		return mydata.listStockNames();
	}
	public Sector getSector(String stockName)
	{
		return mydata.getSector(stockName);
	}
	public Sector getSector(Stock stock)
	{
		return mydata.getSector(stock.company_name());
	}
	////////////////////////////////////////
	//	supporting routines
	private int getTickIndex(Date date)
	{
		long timenow = date.getTime();
		long tickindex = (timenow - mydata.getMarketStartTimeOfToday()) * DataAPI.numberTicksPerDay / mydata.getMarketActiveTimeDuration();
		if (tickindex < 0) tickindex = 0;
		if (tickindex > DataAPI.numberTicksPerDay - 1) tickindex = DataAPI.numberTicksPerDay - 1;
		return (int)tickindex;
	}
}
